package org.demo.ftp;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;


/**
 *  
 * @author  
 * @date    2011-1-22
 * @file    org.demo.ftp.FtpProxy.java
 */
public class FtpProxy {

	// ftp 客户端
	private FTPClient client = new FTPClient();
	// 上传/下载状态队列
	private BlockingQueue<StatusInfo> statusQueue = new LinkedBlockingQueue<StatusInfo>();
	// 状态更新线程
	private Thread statusThread = null;
	
	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		String host = "192.168.1.106";
		String user = "ftpuser1";
		String pass = "pass1";
		
		FtpProxy t = new FtpProxy();
		t.login(host, user, pass);
		t.upload("宁静的和平.flv", "D:\\Temp\\宁静的和平.flv");
		t.download("宁静的和平.flv", "d:\\Temp\\宁静的和平2.flv");
		t.list();	
	}
	/**
	 * 构造函数
	 */
	public FtpProxy(){
		statusThread = new Thread(new UpdateUITask(statusQueue));
		statusThread.setDaemon(true);
		statusThread.start();
	}
	/**
	 * 登录 ftp 服务器
	 * @param host
	 * @param user
	 * @param pass
	 * @return
	 */
	public boolean login(String host, String user, String pass){
		boolean result = false;
		try {
			client.connect(host);
			client.login(user, pass);
			client.enterLocalPassiveMode();
			client.setControlEncoding("utf-8");
			client.addProtocolCommandListener(new PrintConsoleListener(new PrintWriter(System.out)));
			result = true;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}
	/**
	 * 登录 ftp 服务器
	 * @param host
	 * @param user
	 * @param pass
	 * @param port
	 * @return
	 */
	public boolean login(String host, String user, String pass, int port){
		boolean result = false;
		try {
			client.connect(host, port);
			client.login(user, pass);
			client.enterLocalPassiveMode();
			client.setControlEncoding("utf-8");
			client.addProtocolCommandListener(new PrintConsoleListener(new PrintWriter(System.out)));
			result = true;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}
	/**
	 * 显示文件列表
	 * @throws IOException
	 */
	public void list() throws IOException{		
		FTPFile[] files = client.listFiles();
		for (FTPFile file : files){
			if (file.isDirectory()){
				System.out.println(" dir: " + file.getName());
			} else {
				System.out.println("file: " + file.getName());
			}
		}
	}
	/**
	 * 下载文件
	 * @param remoteFileName
	 * @param localFilePath
	 */
	public boolean download(String remoteFileName, String localFilePath){		
		
		// 1. 校验远程文件是否存在
		String encodeFileName = "";
		FTPFile remoteFile = null;
		try {
			// 需先对文件名编码,否则中文文件名会因乱码问题而获取不到
			encodeFileName = new String(remoteFileName.getBytes(), "iso-8859-1");
			FTPFile[] remoteFiles = client.listFiles(encodeFileName);
			if (remoteFiles.length < 1){
				System.out.println(">> Remote file is not exist : " + remoteFileName);
				return false;
			}
			remoteFile = remoteFiles[0];
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		
		long completeSize = 0;
		long currentFileSize = remoteFile.getSize();
		
		// 2. 校验本地文件是否存在
		boolean localFileExist = false;
		File localFile = new File(localFilePath);	
		if (localFile.exists()){
			if (localFile.length() >= remoteFile.getSize()){
				System.out.println(">> Local fileSize has greater than remote fileSize.");
				return false;
			}
			localFileExist = true;
			completeSize = localFile.length();
			client.setRestartOffset(localFile.length());
		}
		
		// 3. 若本地文件已存在则采用续传模式
		boolean result = false;
		InputStream in = null;
		StatusInfo status = null;
		try {			
			in = client.retrieveFileStream(encodeFileName);
			FileOutputStream fos = new FileOutputStream(localFile, localFileExist);
			byte[] data = new byte[8192];
			int readCnt = -1;
			while ((readCnt = in.read(data)) != -1){
				fos.write(data, 0, readCnt);
				fos.flush();
				completeSize += readCnt;
				// 反馈当前下载进度
				try {
					status = new StatusInfo(
							 localFile.getName(),remoteFileName, 
							 completeSize, currentFileSize, true);
					statusQueue.put(status);
				} catch (InterruptedException e) {
					// Ignore.
				}
			}
			fos.close();
			result = true;
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (in != null){
					in.close(); 
				}
				// 下载完文件后必须调用一次 getReply(),否则命令通道中残留的服务端响应信息会导致后续操作出错
				if (client.getReply() == FTPReply.CLOSING_DATA_CONNECTION){
					System.out.println(">> closing data connection.");
				}
			} catch (Exception e){				
			}
		}
		
		// download complete.
		return result;
	}
	/**
	 * 上传文件到 ftp 服务器
	 * @param fileName
	 * @param filePath
	 * @return
	 */
	public boolean upload(String fileName, String filePath){
		boolean result = false;
		try {
			// 需先对文件名编码, 否则服务端保存的文件名为乱码
			fileName = new String(fileName.getBytes(), "iso-8859-1");
			InputStream in = new FileInputStream(filePath);	
			client.setFileType(FTP.BINARY_FILE_TYPE);
			client.storeFile(fileName, in);
			in.close();
			result = true;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}
}